import axios from 'axios'
import { MessageBox, Notification } from 'element-ui'
import store from '@/store'
import { getToken, setToken, getRefreshToken, setRefreshToken, getTokenTime, setTokenTime } from '@/utils/auth'
import qs from 'qs'
import { refreshToken } from '@/api/sysUser'

// create an axios instance
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  timeout: 5000 // request timeout
})

// Has the token been refreshed
let isRefresh = false

// request interceptor
service.interceptors.request.use(
  config => {
    const curentTime = new Date().getTime()
    const expireTime = getTokenTime()
    const hasToken = getToken()
    if (hasToken && expireTime && expireTime > 0) {
      const intervalTime = (expireTime - curentTime) / 1000 / 60
      if (intervalTime < 30) {
        if (!isRefresh) {
          isRefresh = true
          return refreshToken({ refreshToken: getRefreshToken() }).then(response => {
            if (response.code === 200) {
              const { data } = response
              store.commit('user/SET_TOKEN', data.accessToken)
              setToken(data.accessToken)
              store.commit('user/SET_REFRESH_TOKEN', data.refreshToken)
              setRefreshToken(data.refreshToken)

              const { expiresIn, expiresType } = data
              const timestamp = new Date().getTime()
              let expire = 0
              // 将秒数转为毫秒数
              if (expiresType === 'second') {
                expire = expiresIn * 1000
              }
              // 将分钟转为毫秒数
              if (expiresType === 'minute') {
                expire = expiresIn * 60 * 1000
              }
              // 保存token过期时间
              setTokenTime(timestamp + expire)

              config.headers['Authorization'] = getToken()
              return config
            }
          }).catch(response => {
            console.log(response)
          }).finally(() => {
            isRefresh = false
          })
        }
      }
    }

    if (store.getters.token) {
      config.headers['Authorization'] = getToken()
    }
    return config
  },
  error => {
    return Promise.reject(error)
  }
)

// response interceptor
service.interceptors.response.use(
  response => {
    const res = response.data

    if (res.code === 1001) { // 校验验证码失败
      Notification.error({
        title: '系统提示',
        message: res.msg
      })
    } else if (res.code === 1002 || res.code === 1003) { // 用户token过期
      MessageBox.confirm('用户登录信息过期，请重新登录！', '系统提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        store.dispatch('user/resetToken').then(() => {
          location.reload()
        })
      })
    } else if (res.code !== 200) { // 系统异常情况
      Notification.error({
        title: '系统提示',
        message: res.msg
      })
    }

    return res
  },
  error => {
    return Promise.reject(error)
  }
)

function filterNonNull(obj) {
  return Object.fromEntries(Object.entries(obj).filter(([k, v]) => v))
}

const http = {
  get(url, params) {
    return service.get(url, {
      params: params,
      paramsSerializer: (params) => {
        return qs.stringify(filterNonNull(params), { arrayFormat: 'brackets' })
      }
    })
  },
  delete(url, params) {
    return service.delete(url, {
      params: params,
      paramsSerializer: (params) => {
        return qs.stringify(filterNonNull(params), { arrayFormat: 'brackets' })
      }
    })
  },
  post(url, params) {
    return service.post(url, params, {
      transformRequest: [(params) => {
        return JSON.stringify(params)
      }],
      headers: {
        'Content-Type': 'application/json;charset=UTF-8'
      }
    })
  },
  put(url, params) {
    return service.put(url, params, {
      transformRequest: [(params) => {
        return JSON.stringify(params)
      }],
      headers: {
        'Content-Type': 'application/json;charset=UTF-8'
      }
    })
  },
  form(url, params) {
    return service.post(url, params, {
      transformRequest: [(params) => {
        return qs.stringify(params)
      }],
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    })
  },
  upload(url, params) {
    return service.post(url, params)
  }
}

export default http
